﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Xml;

namespace ArabDynamicsUtility
{
    /// <summary>
    /// Fecth embed code from Url
    /// </summary>
    public partial class Url2Embed
    {
        /// <summary>
        /// Current provider object
        /// </summary>
        private provider pryObjProvider { get; set; }

        /// <summary>
        /// Media Ids as MatchCollection
        /// </summary>
        private MatchCollection pryLstMediaId { get; set; }

        /// <summary>
        ///  Parse given URL
        /// </summary>
        /// <param name="strUrl">url check for embeded video as string</param>
        /// <returns>Url2Embed object which contains the info</returns>
        public static Url2Embed parseUrl(string strUrl)
        {
            // create instance of Url2Embed to hold the result
            Url2Embed objUrlToEmbed = new Url2Embed();

            // trim url
            strUrl = strUrl.Trim();

            // fetch default providers list
            List<provider> lstDefaultProviders = provider.getDefaultProviders();

            // iterate through providers
            foreach (provider objProvider in lstDefaultProviders)
            {
                // call Regex.Matches get all url matchs with provider pattern
                MatchCollection lstMatches = Regex.Matches(strUrl, objProvider.pryUrlMatch, RegexOptions.IgnoreCase);
                // check if there url match provider pattern
                if (lstMatches.Count > 0) 
                {
                    // assign current Provider object to UrlToEmbed
                    objUrlToEmbed.pryObjProvider = objProvider;

                    // Check if this provider needs to parse html from url to get info
                    if ( !string.IsNullOrEmpty(objProvider.pryFetchMatch) ) 
                    {
                        // parse html from url to get info
                        parseHtmlFromUrl(strUrl, objUrlToEmbed);

                        // return UrlToEmbed object
                        return objUrlToEmbed; 
                    } else {
                        // assing current Provider MatchCollection to UrlToEmbed
                        objUrlToEmbed.pryLstMediaId = lstMatches;

                        // return UrlToEmbed object
                        return objUrlToEmbed; 
                    }
                }
            }

            // return empty UrlToEmbed object
            return objUrlToEmbed;      
        }

        /// <summary>
        /// Attempt to parse the embed id from a given URL
        /// </summary>
        /// <param name="strUrl"></param>
        /// <param name="objUrlToEmbed"></param>
        /// <returns></returns>
        private static bool parseHtmlFromUrl(string strUrl, Url2Embed objUrlToEmbed) {
            // use WebClient to read html from url
            using (WebClient client = new WebClient ()) // WebClient class inherits IDisposable
            {
                // read html as stream from url
                Stream data = client.OpenRead(strUrl);
                // convert Stream to StreamReader and call ReadToEnd method to get html as string
                string strHtml = (new StreamReader (data)).ReadToEnd();
                strHtml = Regex.Replace(strHtml,"/[^(\x20-\x7F)]*/","");
                // call Regex.Matches get all url matchs with provider pattern
                MatchCollection lstMatches = Regex.Matches(strHtml, objUrlToEmbed.pryObjProvider.pryFetchMatch, RegexOptions.IgnoreCase);
                // check if there url match provider pattern
                if (lstMatches.Count > 0) 
                {
                    // assing current Provider MatchCollection to UrlToEmbed
                    objUrlToEmbed.pryLstMediaId = lstMatches;
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Convert the url to an embedable tag
        /// </summary>
        /// <param name="strWidth"></param>
        /// <param name="strHeight"></param>
        /// <returns>return the embed html as string</returns>
        public string getEmbedCode(string strWidth ="", string strHeight="") {
            // check is Provider is not null
            if(this.pryObjProvider == null){
                return string.Empty;
            }

            // check if witch is not set use the default Width based on provider value
            if(string.IsNullOrEmpty(strWidth))
            {
                // assign default Width based on provider value
                strWidth = this.pryObjProvider.pryEmbedWidth;
            }

            // check if witch is not set use the default Height based on provider value
            if (string.IsNullOrEmpty(strHeight))
            {
                // assign default Height based on provider value
                strHeight = this.pryObjProvider.pryEmbedHeight;
            }

            // check Provider is using Iframe
            if (!string.IsNullOrEmpty(this.pryObjProvider.pryIframePlayer))
            {
                // build iFrame and return it as string
                return this.buildiFrame(strWidth, strHeight);
            }
            // build Object and return it as string
            return this.buildObject(strWidth, strHeight);
        }

        /// <summary>
        /// Return a thumbnail for the embeded video
        /// </summary>
        /// <returns>string - the thumbnail url</returns>
        public string getImageURL() {
            // check is Provider is not null
            if (this.pryObjProvider == null)
            {
                return string.Empty;
            }
            // check Provider has url format for thumbnail image 
            if (!string.IsNullOrEmpty(this.pryObjProvider.pryThumbImageSrc))
            {
                string strThumbUrl = this.pryObjProvider.pryThumbImageSrc;
                // iterate through provider MatchCollection to get id(s)
                for (int i = 1; i < this.pryLstMediaId[0].Groups.Count; i++)
                {
                    // fill image url placeholders
                    strThumbUrl = strThumbUrl.Replace("$" + (i + 1), this.pryLstMediaId[0].Groups[i].Value);
                }
                // return image url
                return strThumbUrl;
            }
            // check Provider needs API to get thumbnail image info 
            else if (!string.IsNullOrEmpty(this.pryObjProvider.pryThumbImageApiUrl))
            {
                string strApiUrl = this.pryObjProvider.pryThumbImageApiUrl;

                // iterate through provider MatchCollection to get id(s)
                for (int i = 1; i < this.pryLstMediaId[0].Groups.Count; i++)
                {
                    // fill API url placeholders
                    strApiUrl = strApiUrl.Replace("$" + (i + 1), this.pryLstMediaId[0].Groups[i].Value);
                }

                // use WebClient to read response from api url
                using (WebClient client = new WebClient()) // WebClient class inherits IDisposable
                {
                    // read response as stream from Api url
                    Stream data = client.OpenRead(strApiUrl);
                    // convert Stream to StreamReader and call ReadToEnd method to get response as string
                    string strData = (new StreamReader(data)).ReadToEnd();
                    string strThumbUrl = string.Empty;
                    // try to Parse response as XML and retrieve image url
                    if (tryParseXML(strData, ref  strThumbUrl))
                    {
                        // return image url
                        return strThumbUrl;
                    }
                    // try to Parse response as JSON and retrieve image url
                    else if (tryParseJson(strData, ref  strThumbUrl))
                    {
                        // return image url
                        return strThumbUrl;
                    }
                }
            }
            // return empty string as image url
            return string.Empty;
        }

        /// <summary>
        /// try to Parse response as XML and retrieve image url
        /// </summary>
        /// <param name="strXML"></param>
        /// <param name="strThumbUrl"></param>
        /// <returns></returns>
        private bool tryParseXML(string strXML, ref string strThumbUrl)
        {
            try
            {
                // create an xml document object
                XmlDocument xmlDoc = new XmlDocument();
                // load the XML document from string
                xmlDoc.LoadXml(strXML);
                // Find spisifc node by node name
                XmlNodeList objXmlNodeList = xmlDoc.GetElementsByTagName(this.pryObjProvider.pryThumbImageApiAttName);
                // check if it founds the spisifc node
                if (objXmlNodeList.Count > 0)
                {
                    // assig current node value to image url variable as call by refrance
                    strThumbUrl = objXmlNodeList[0].InnerText;
                }
                return true;
            }
            catch (Exception)
            {
            }
            return false;
        }

        /// <summary>
        /// try to Parse response as XML and retrieve image url
        /// </summary>
        /// <param name="strJson"></param>
        /// <param name="strThumb"></param>
        /// <returns></returns>
        private bool tryParseJson(string strJson, ref string strThumb)
        {
            try
            {
                // parse json
                JToken json = JValue.Parse(strJson);

                // iterate through json items
                foreach (JToken objJToken in json.Values())
                {
                    // check if its the needed property item
                    if (objJToken is JProperty && ((JProperty)objJToken).Name == this.pryObjProvider.pryThumbImageApiAttName)
                    {
                        // assig current node value to image url variable as call by refrance
                        strThumb = ((JProperty)objJToken).Value.ToString();
                        break;
                    }
                }
                return true;
            }
            catch (Exception)
            {
            }

            return false;
        }

        /// <summary>
        /// Build a generic object skeleton
        /// </summary>
        /// <param name="strWidth"></param>
        /// <param name="strHeight"></param>
        /// <returns></returns>
        private string buildObject(string strWidth, string strHeight)
        {
            string strSource = this.pryObjProvider.pryEmbedSrc;
            string strFlashvars = (!string.IsNullOrEmpty(this.pryObjProvider.pryFlashVars)) ? this.pryObjProvider.pryFlashVars : "";
            for (int i = 1; i < this.pryLstMediaId[0].Groups.Count; i++) 
            {
                strSource = strSource.Replace("$" + (i+1), this.pryLstMediaId[0].Groups[i].Value);
                strFlashvars = strFlashvars.Replace("$" + (i+1), this.pryLstMediaId[0].Groups[i].Value);
            }
            strSource = strSource.Replace("\"","&quot;");
            strFlashvars = strFlashvars.Replace("\"","&quot;");
            Dictionary<string, string> dicObjectParams = new Dictionary<string, string>();
            dicObjectParams.Add("movie", strSource);
            dicObjectParams.Add("quality", "high");
            dicObjectParams.Add("allowFullScreen", "true");
            dicObjectParams.Add("allowScriptAccess", "always");
            dicObjectParams.Add("pluginspage", "http://www.macromedia.com/go/getflashplayer");
            dicObjectParams.Add("autoplay", "false");
            dicObjectParams.Add("autostart", "false");
            dicObjectParams.Add( "flashvars", strFlashvars);
            Dictionary<string, string> dicObjectAttribs = new Dictionary<string, string>();
            dicObjectAttribs.Add("type", "application/x-shockwave-flash");
            dicObjectAttribs.Add("data", strSource);
            dicObjectAttribs.Add("width", strWidth);
            dicObjectAttribs.Add("height",  strHeight);
            string strObjectAttribs = "";
            string strObjectParams = "";
            foreach (string strParam in dicObjectAttribs.Keys) {
              strObjectAttribs += "  " + strParam + "=\"" + dicObjectAttribs[strParam] + "\"";    
            }
            foreach (string strParam in dicObjectParams.Keys) {
              strObjectParams += "<param name=\"" + strParam + "\" value=\"" + dicObjectParams[strParam] + "\" />";
            }
            return string.Format("<object {0}>{1}</object>", strObjectAttribs, strObjectParams);
        }

        /// <summary>
        /// Build an iFrame player
        /// </summary>
        /// <param name="strWidth"></param>
        /// <param name="strHeight"></param>
        /// <returns></returns>
        private string buildiFrame(string strWidth, string strHeight) {
            string source = this.pryObjProvider.pryIframePlayer;
            for (int i=1; i< this.pryLstMediaId[0].Groups.Count; i++) {
                source = source.Replace("$" + (i+1), this.pryLstMediaId[0].Groups[i].Value);
            }
            return string.Format("<iframe type=\"text/html\" width=\"" + strWidth + "\" height=\"" + strHeight + "\" src=\"{0}\" scrolling=\"no\" frameborder=\"0\"></iframe>", source);
        }
    }
}
